from django.http import Http404
from rest_framework import exceptions
from rest_framework_simplejwt.exceptions import InvalidToken
from django.core.exceptions import PermissionDenied
from rest_framework.views import set_rollback
import traceback

from framework.response import response
from utils.value_dispath import value_dispatch

from framework import Code


class _BaseException(Exception):
    def __init__(self, message):
        self.message = message

    def __str__(self):
        return self.message


class TDEngineRequestException(_BaseException):
    """tdengine 异常类"""


def get_class_name(cls):
    return cls.__name__


@value_dispatch
def get_response_code(exc) -> int:
    """重定义 response code"""
    return Code.C_5_10


@get_response_code.register_for_all([get_class_name(exceptions.NotAuthenticated), get_class_name(InvalidToken)])
def not_authenticated(exc):
    """jwt 认证失败 没有携带token请求 token过期"""
    return Code.C_4_1


@get_response_code.register(get_class_name(exceptions.ValidationError))
def not_validation(exc):
    """视图参数验证失败"""
    return Code.C_4_0


@get_response_code.register(get_class_name(exceptions.PermissionDenied))
def permission_denied(exc):
    """没有权限访问"""
    return Code.C_4_3


@get_response_code.register(get_class_name(exceptions.MethodNotAllowed))
def permission_denied(exc):
    """不支持的请求方式"""
    return Code.C_4_5


@get_response_code.register(get_class_name(exceptions.NotFound))
def permission_denied(exc):
    """http 404"""
    return Code.C_4_4


def exec_handler(exc, context):
    """
    Returns the response that should be used for any given exception.

    By default we handle the REST framework `APIException`, and also
    Django's built-in `Http404` and `PermissionDenied` exceptions.

    Any unhandled exceptions may return `None`, which will cause a 500 error
    to be raised.
    """
    if isinstance(exc, Http404):
        exc = exceptions.NotFound(*(exc.args))
    elif isinstance(exc, PermissionDenied):
        exc = exceptions.PermissionDenied(*(exc.args))

    if isinstance(exc, exceptions.APIException):
        headers = {}
        if getattr(exc, 'auth_header', None):
            headers['WWW-Authenticate'] = exc.auth_header
        if getattr(exc, 'wait', None):
            headers['Retry-After'] = '%d' % exc.wait

        if isinstance(exc.detail, (list, dict)):
            data = exc.detail
        else:
            data = {'detail': exc.detail}
        set_rollback()
    else:
        # 其他异常 统计处理
        data = traceback.format_exc()
    # 重置 响应code
    code = get_response_code(exc.__class__.__name__)
    return response(message='fail', code=code, data=data)
